/**
 * @BusiMixedEncoder.java  COPYRIGHT xj
 * 
 * Created on 2017年7月20日 下午4:44:31
 */
package xj.toolkit.access.busi.codec;

import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import xj.toolkit.bean.CommonsHeader;
import xj.toolkit.util.MutableIdentifyable;
import xj.toolkit.util.MutablePropertyable;
import xj.toolkit.access.AccessHeader;
import xj.toolkit.access.AccessMsgCodeConstants;
import xj.toolkit.access.msg.AccessAckMessage;

/**
 * @author <a href="mailto:cxj2000@gmail.com">xj.cao</a>
 *
 */
public abstract class BusiMixedEncoder extends MessageToByteEncoder<MutableIdentifyable> {
	
	private static final Logger logger = LoggerFactory.getLogger(BusiMixedEncoder.class);
	
	/**
	 * 得到消息标识。
	 * 
	 * @param msg 消息。
	 * @return 消息标识。
	 */
	protected abstract int getMsgCode(MutableIdentifyable msg);
	
	/**
	 * 将消息内容转换为字节数组。
	 * 
	 * @param msg
	 * @return
	 */
	protected abstract byte[] build(MutableIdentifyable msg);

	@Override
	protected void encode(ChannelHandlerContext ctx, MutableIdentifyable msg, ByteBuf out) throws Exception {
		// -- ack消息单独处理。
		int msgCode = 0;
		if (msg instanceof AccessAckMessage) {
			msgCode = AccessMsgCodeConstants.MSG_CODE_ACK;
		} else {
			msgCode = getMsgCode(msg);
		}
		if (msgCode == 0) {
			throw new RuntimeException(
					"invalid message, missing msgCode.");
		}
		
		if (!(msg instanceof MutablePropertyable)){
			throw new RuntimeException(
					"invalid message, not MutablePropertyable .");
		}
		
		AccessHeader accessHeader = (AccessHeader) ((MutablePropertyable)msg).getProperty(AccessHeader.KEY);
		if (accessHeader == null) {
			throw new RuntimeException(
					"invalid message, cannot found AccessHeader.");
		}
		
		final UUID id = ((MutableIdentifyable) msg).getIdentification();
		if (logger.isDebugEnabled()) {
			logger.debug("encoding JSONObject {} to wrappedBuffer", msg);
		}
		
		if (null == id && logger.isWarnEnabled()) {
			logger.warn("{} is json but missing transactionId", msg);
			return;
		}

		final byte[] bytes = build(msg);
		
		// -- 组装头
		CommonsHeader header = new CommonsHeader();
		header.setMessageCode(msgCode);
		header.setFirstTransaction(id.getMostSignificantBits());
		header.setSecondTransaction(id.getLeastSignificantBits());
		
		// -- 写入数据。
		out.writeByte(header.getBasicVer());
		out.writeShort(header.getPayloadType());
		out.writeShort(header.getType());
		out.writeLong(header.getFirstTransaction());
		out.writeLong(header.getSecondTransaction());
		out.writeInt(header.getReserved());
		out.writeInt(msgCode);
		out.writeInt(bytes.length + AccessHeader.HEADER_LENGTH);
		
		out.writeShort(accessHeader.getSourceModuleId());
		out.writeShort(accessHeader.getSourceInstanceId());
		out.writeShort(accessHeader.getTargetModuleId());
		out.writeShort(accessHeader.getTargetInstanceId());
		out.writeInt(accessHeader.getReserved());
		
		out.writeBytes(bytes);
	
	}

}
